﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Forms.Integration;
using ZCustomControl.Models;

namespace ZCustomControl.Controls
{
    /// <summary>
    /// 按照步骤 1a 或 1b 操作，然后执行步骤 2 以在 XAML 文件中使用此自定义控件。
    ///
    /// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。
    /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根 
    /// 元素中: 
    ///
    ///     xmlns:vp="clr-namespace:VideoPlayer"
    ///
    ///
    /// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。
    /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根 
    /// 元素中: 
    ///
    ///     xmlns:vp="clr-namespace:VideoPlayer;assembly=VideoPlayer"
    ///
    /// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用，
    /// 并重新生成以避免编译错误: 
    ///
    ///     在解决方案资源管理器中右击目标项目，然后依次单击
    ///     “添加引用”->“项目”->[选择此项目]
    ///
    ///
    /// 步骤 2)
    /// 继续操作并在 XAML 文件中使用控件。
    ///
    ///     <vp:VideoPlayer/>
    ///
    /// </summary>
    public class VideoPlayer : Control
    {
        #region Fields
        
        private System.Windows.Forms.Panel _panel = null;
        private WindowsFormsHost _wfi = null;
        private Button _btnPlay = null;
        private Button _btnPause = null;
        private Button _btnStop = null;
        private Button _btnVoice = null;
        private Popup _popVoice = null;
        private Slider _sldVoice = null;

        private IntPtr _viewHandle = IntPtr.Zero;

        #endregion

        #region Properties

        public IntPtr ViewHandle
        {
            get { return _viewHandle; }
        }

        #endregion

        #region Dependency Properties

        public static readonly DependencyProperty VoicePopupHorizontalOffsetProperty
            = DependencyProperty.Register("VoicePopupHorizontalOffset", typeof(double), typeof(VideoPlayer), new PropertyMetadata(0d, null));
        public static readonly DependencyProperty VoicePopupVerticalOffsetProperty
            = DependencyProperty.Register("VoicePopupVerticalOffset", typeof(double), typeof(VideoPlayer), new PropertyMetadata(0d, null));
        public static readonly DependencyProperty VoiceValueProperty
            = DependencyProperty.Register("VoiceValueProperty", typeof(int), typeof(VideoPlayer), new PropertyMetadata(0, OnVoiceValuePropertyChangedCallback));
        public static readonly DependencyProperty VideoPlayStatusProperty
            = DependencyProperty.Register("VideoPlayStatus", typeof(PlayStatus), typeof(VideoPlayer), new PropertyMetadata(PlayStatus.Stop, OnVideoPlayStatusPropertyChangedCallback));

        #endregion

        #region Dependency Property Wrappers

        public double VoicePopupHorizontalOffset
        {
            get
            {
                return (double)GetValue(VoicePopupHorizontalOffsetProperty);
            }
            set
            {
                SetValue(VoicePopupHorizontalOffsetProperty, value);
            }
        }

        public double VoicePopupVerticalOffset
        {
            get
            {
                return (double)GetValue(VoicePopupVerticalOffsetProperty);
            }
            set
            {
                SetValue(VoicePopupVerticalOffsetProperty, value);
            }
        }

        public int VoiceValue
        {
            get { return (int)GetValue(VoiceValueProperty); }
            set { SetValue(VoiceValueProperty, value); }
        }

        public PlayStatus VideoPlayStatus
        {
            get { return (PlayStatus)GetValue(VideoPlayStatusProperty); }
            set { SetValue(VideoPlayStatusProperty, value); }
        }

        #endregion

        #region Dependency Property Changed Callback

        private static void OnVoiceValuePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            VideoPlayer vp = d as VideoPlayer;
            if (vp == null)
            {
                return;
            }

            if (vp._sldVoice == null)
            {
                return;
            }

            int newVoiceValue = (int)e.NewValue;
            if (((int)vp._sldVoice.Value) != newVoiceValue)
            {
                vp._sldVoice.Value = newVoiceValue;
            }
        }

        private static void OnVideoPlayStatusPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            VideoPlayer vp = d as VideoPlayer;
            if (vp == null)
            {
                return;
            }

            PlayStatus playStatus = (PlayStatus)e.NewValue;
            if (playStatus == PlayStatus.Stop || playStatus == PlayStatus.Pause)
            {
                if (vp._btnPlay != null)
                {
                    vp._btnPlay.Visibility = Visibility.Visible;
                }
                if (vp._btnPause != null)
                {
                    vp._btnPause.Visibility = Visibility.Collapsed;
                }
            }
            else
            {
                if (vp._btnPlay != null)
                {
                    vp._btnPlay.Visibility = Visibility.Collapsed;
                }
                if (vp._btnPause != null)
                {
                    vp._btnPause.Visibility = Visibility.Visible;
                }
            }
        }

        #endregion

        #region RoutedEvents

        public static readonly RoutedEvent VideoPlayEvent
            = EventManager.RegisterRoutedEvent("VideoPlay", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(VideoPlayer));
        public static readonly RoutedEvent VideoPauseEvent
            = EventManager.RegisterRoutedEvent("VideoPause", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(VideoPlayer));
        public static readonly RoutedEvent VideoStopEvent
            = EventManager.RegisterRoutedEvent("VideoStop", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(VideoPlayer));
        public static readonly RoutedEvent VoiceValueChangedEvent
            = EventManager.RegisterRoutedEvent("VoiceValueChangedEvent", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<int>), typeof(VideoPlayer));

        #endregion

        #region Routed Event Wrappers

        public event RoutedEventHandler VideoPlay
        {
            add { AddHandler(VideoPlayEvent, value); }
            remove { RemoveHandler(VideoPlayEvent, value); }
        }

        public event RoutedEventHandler VideoPause
        {
            add { AddHandler(VideoPauseEvent, value); }
            remove { RemoveHandler(VideoPauseEvent, value); }
        }

        public event RoutedEventHandler VideoStop
        {
            add { AddHandler(VideoStopEvent, value); }
            remove { RemoveHandler(VideoStopEvent, value); }
        }

        public event RoutedPropertyChangedEventHandler<int> VoiceValueChanged
        {
            add { AddHandler(VoiceValueChangedEvent, value); }
            remove { RemoveHandler(VoiceValueChangedEvent, value); }
        }

        #endregion

        #region Construcotrs

        static VideoPlayer()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(VideoPlayer), new FrameworkPropertyMetadata(typeof(VideoPlayer)));
        }

        #endregion

        #region Public Methods

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _wfi = GetTemplateChild("Part_WinFormHost") as WindowsFormsHost;
            if(_wfi != null)
            {
                _panel = new System.Windows.Forms.Panel();
                _panel.BackColor = System.Drawing.Color.Black;
                _wfi.Child = _panel;
                _viewHandle = _panel.Handle;
            }

            _btnPlay = GetTemplateChild("PART_BTNPlay") as Button;
            if (_btnPlay != null)
            {
                _btnPlay.Click += _btnPlay_Click;
            }

            _btnPause = GetTemplateChild("PART_BTNPause") as Button;
            if (_btnPause != null)
            {
                _btnPause.Click += _btnPause_Click;
            }

            _btnStop = GetTemplateChild("PART_BTNStop") as Button;
            if (_btnStop != null)
            {
                _btnStop.Click += _btnStop_Click;
            }

            _btnVoice = GetTemplateChild("PART_BTNVoice") as Button;
            if (_btnVoice != null)
            {
                _btnVoice.Click += _btnVoice_Click;
            }

            _popVoice = GetTemplateChild("PART_PopVoice") as Popup;

            _sldVoice = GetTemplateChild("PART_SliderVoice") as Slider;
            if (_sldVoice != null)
            {
                _sldVoice.ValueChanged += _sldVoice_ValueChanged;
            }
        }

        #endregion

        #region Event Methods

        private void _btnStop_Click(object sender, RoutedEventArgs e)
        {
            RoutedEventArgs args = new RoutedEventArgs(null, null);
            args.RoutedEvent = VideoStopEvent;
            RaiseEvent(args);
        }

        private void _btnPlay_Click(object sender, RoutedEventArgs e)
        {
            RoutedEventArgs args = new RoutedEventArgs(null, null);
            args.RoutedEvent = VideoPlayEvent;
            RaiseEvent(args);
        }

        private void _btnPause_Click(object sender, RoutedEventArgs e)
        {
            RoutedEventArgs args = new RoutedEventArgs(null, null);
            args.RoutedEvent = VideoPauseEvent;
            RaiseEvent(args);
        }

        private void _sldVoice_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            int newVoiceValue = (int)_sldVoice.Value;
            if (newVoiceValue == VoiceValue)
            {
                return;
            }

            int oldValue = VoiceValue;
            VoiceValue = newVoiceValue;
            RoutedPropertyChangedEventArgs<int> args = new RoutedPropertyChangedEventArgs<int>(oldValue, newVoiceValue);
            args.RoutedEvent = VoiceValueChangedEvent;
            RaiseEvent(args);
        }

        private void _btnVoice_Click(object sender, RoutedEventArgs e)
        {
            Button btnVoice = sender as Button;
            if (btnVoice == null)
            {
                return;
            }

            _popVoice.PlacementTarget = btnVoice;
            _popVoice.HorizontalOffset = VoicePopupHorizontalOffset;
            _popVoice.VerticalOffset = VoicePopupVerticalOffset;
            _popVoice.IsOpen = true;
        }

        #endregion
    }
}
